﻿using System;
using System.Collections.Generic;

using System.Text;
using ClearCanvas.Dicom.Network;
using ClearCanvas.Dicom.Utilities.Statistics;
using ClearCanvas.Dicom;
using System.Net;
using DicomScu.Scu;

namespace DicomScu
{
    public class DicomServerHandler : IDicomServerHandler
    {
        #region Private Member
        private AssociationStatisticsRecorder _statsRecorder;
        private String _folderName = String.Empty;

        #endregion
        #region Constructor
        public DicomServerHandler(DicomServer server, ServerAssociationParameters association, String folderName)
        {
            _statsRecorder = new AssociationStatisticsRecorder(server);
            _folderName = folderName;

        }
        #endregion
        #region IDicomServerHandler Members

        public void OnReceiveAssociateRequest(DicomServer server, ServerAssociationParameters association)
        {
            //throw new NotImplementedException();
            server.SendAssociateAccept(association);
        }

        public void OnReceiveRequestMessage(DicomServer server, ServerAssociationParameters association, byte presentationID, ClearCanvas.Dicom.DicomMessage message)
        {
            if (message.DataSet.Count == 0)
            {
                //Verifier
                server.SendCEchoResponse(presentationID, message.MessageId, DicomStatuses.Success);
                Logger.WriteLog("Verified Success");
            }
            else
            {
                if (message.CommandField == DicomCommandField.CFindRequest)
                {
                    DicomMessage _respone = new DicomMessage();
                    ////DicomMessage _mss = new DicomMessage();

                    message.DataSet[DicomTags.PatientId].SetStringValue("aaaa");
                    message.DataSet[DicomTags.PatientsName].SetStringValue("aaaa");
                    message.DataSet[DicomTags.PatientsSex].SetStringValue("aaaa");
                    //message.DataSet[DicomTags.PatientsBirthDate].SetStringValue("aaaa");
                    message.DataSet[DicomTags.StudyId].SetStringValue("aaaa");
                    message.DataSet[DicomTags.StudyInstanceUid].SetStringValue("bbbb");
                    // message.DataSet[DicomTags.StudyDate].SetStringValue("aaaa");
                    //message.DataSet[DicomTags.StudyTime].SetStringValue("aaaa");
                    message.DataSet[DicomTags.Modality].SetStringValue("aaaa");
                    //message.DataSet[DicomTags.SeriesNumber].SetStringValue("aaaa");
                    //message.DataSet[DicomTags.SeriesDate].SetStringValue("aaaa");
                    //message.DataSet[DicomTags.SeriesTime].SetStringValue("aaaa");

                    string query = message.DataSet[DicomTags.QueryRetrieveLevel].GetString(0, "");


                    server.SendCFindResponse(presentationID, message.MessageId, message, DicomStatuses.Pending);
                    server.SendCFindResponse(presentationID, message.MessageId, _respone, DicomStatuses.Success);
                }
                else if (message.CommandField == DicomCommandField.CStoreRequest)
                {
                    //Received dicom object
                    DicomUid sopInstanceUid;

                    bool ok = message.DataSet[DicomTags.SopInstanceUid].TryGetUid(0, out sopInstanceUid);
                    if (ok)
                    {
                        //Stored Dicom object

                        string fileName = sopInstanceUid.ToString();
                        string path = String.Format("{0}\\{1}.dcm", _folderName, fileName);

                        try
                        {
                            DicomFile dicomFile = new DicomFile(message, path);

                            if (message.TransferSyntax.Encapsulated)
                                dicomFile.TransferSyntax = message.TransferSyntax;
                            else
                                dicomFile.TransferSyntax = TransferSyntax.ExplicitVrLittleEndian;

                            dicomFile.MediaStorageSopInstanceUid = sopInstanceUid.UID;
                            dicomFile.ImplementationClassUid = DicomImplementation.ClassUID.UID;
                            dicomFile.ImplementationVersionName = DicomImplementation.Version;
                            dicomFile.SourceApplicationEntityTitle = association.CallingAE;
                            dicomFile.MediaStorageSopClassUid = message.SopClass.Uid;

                            dicomFile.Save(DicomWriteOptions.None);


                            server.SendCStoreResponse(presentationID, message.MessageId,
                                                      sopInstanceUid.UID, DicomStatuses.Success);
                            Logger.WriteLog("Received Dicom Object: " + sopInstanceUid.UID.ToString());
                        }
                        catch (Exception ex)
                        {
                            server.SendCStoreResponse(presentationID, message.MessageId, sopInstanceUid.UID,
                                DicomStatuses.ProcessingFailure);
                            Logger.WriteLog(ex.Message);
                        }
                    }
                    else
                    {
                        //Response for Client transfer next object
                        server.SendCStoreResponse(presentationID, message.MessageId, sopInstanceUid.UID,
                        DicomStatuses.ProcessingFailure);

                        Logger.WriteLog("Received processing Failure");
                    }
                }

            }
        }

        public void OnReceiveResponseMessage(DicomServer server, ServerAssociationParameters association, byte presentationID, ClearCanvas.Dicom.DicomMessage message)
        {
            server.SendAssociateAbort(DicomAbortSource.ServiceUser, DicomAbortReason.UnexpectedPDU);
        }

        public void OnReceiveReleaseRequest(DicomServer server, ServerAssociationParameters association)
        {

        }

        public void OnReceiveAbort(DicomServer server, ServerAssociationParameters association, DicomAbortSource source, DicomAbortReason reason)
        {
            Logger.WriteLog("Receive Abort " + reason.ToString());
        }

        public void OnNetworkError(DicomServer server, ServerAssociationParameters association, Exception e)
        {
            Logger.WriteLog("Network Error " + e.Message);
        }

        public void OnDimseTimeout(DicomServer server, ServerAssociationParameters association)
        {
            Logger.WriteLog("Dimse Timeout");
        }

        #endregion

        #region IDicomServerHandler Members

        public void OnCompletedReceived()
        {

        }

        #endregion


        #region
        public static string LocalStoreDirectoryConfig
        {
            get;
            set;
        }
        static ServerAssociationParameters _para;
        public static bool IsStarted;
        public static void StartListenning(ScuConfig localScu )
        {
            if (localScu == null)
                return;
            #region Add Syntax
            IPEndPoint _endpoint = new IPEndPoint(IPAddress.Any, localScu.RemotePort);
            _para = new ServerAssociationParameters(localScu.LocalAE, _endpoint);
            byte pcid = _para.AddPresentationContext(SopClass.VerificationSopClass);

            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.Jpeg2000ImageCompressionLosslessOnly);
            _para.AddTransferSyntax(pcid, TransferSyntax.Jpeg2000ImageCompression);
            _para.AddTransferSyntax(pcid, TransferSyntax.JpegLosslessNonHierarchicalFirstOrderPredictionProcess14SelectionValue1);
            _para.AddTransferSyntax(pcid, TransferSyntax.RleLossless);
            _para.AddTransferSyntax(pcid, TransferSyntax.JpegBaselineProcess1);

            pcid = _para.AddPresentationContext(SopClass.CtImageStorage);

            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.Jpeg2000ImageCompressionLosslessOnly);
            _para.AddTransferSyntax(pcid, TransferSyntax.Jpeg2000ImageCompression);
            _para.AddTransferSyntax(pcid, TransferSyntax.JpegLosslessNonHierarchicalFirstOrderPredictionProcess14SelectionValue1);
            _para.AddTransferSyntax(pcid, TransferSyntax.RleLossless);
            _para.AddTransferSyntax(pcid, TransferSyntax.JpegBaselineProcess1);

            pcid = _para.AddPresentationContext(SopClass.RtDoseStorage);

            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.Jpeg2000ImageCompressionLosslessOnly);
            _para.AddTransferSyntax(pcid, TransferSyntax.Jpeg2000ImageCompression);
            _para.AddTransferSyntax(pcid, TransferSyntax.JpegLosslessNonHierarchicalFirstOrderPredictionProcess14SelectionValue1);
            _para.AddTransferSyntax(pcid, TransferSyntax.RleLossless);
            _para.AddTransferSyntax(pcid, TransferSyntax.JpegBaselineProcess1);

            pcid = _para.AddPresentationContext(SopClass.RtStructureSetStorage);

            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.Jpeg2000ImageCompressionLosslessOnly);
            _para.AddTransferSyntax(pcid, TransferSyntax.Jpeg2000ImageCompression);
            _para.AddTransferSyntax(pcid, TransferSyntax.JpegLosslessNonHierarchicalFirstOrderPredictionProcess14SelectionValue1);
            _para.AddTransferSyntax(pcid, TransferSyntax.RleLossless);
            _para.AddTransferSyntax(pcid, TransferSyntax.JpegBaselineProcess1);

            pcid = _para.AddPresentationContext(SopClass.RtPlanStorage);

            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.Jpeg2000ImageCompressionLosslessOnly);
            _para.AddTransferSyntax(pcid, TransferSyntax.Jpeg2000ImageCompression);
            _para.AddTransferSyntax(pcid, TransferSyntax.JpegLosslessNonHierarchicalFirstOrderPredictionProcess14SelectionValue1);
            _para.AddTransferSyntax(pcid, TransferSyntax.RleLossless);
            _para.AddTransferSyntax(pcid, TransferSyntax.JpegBaselineProcess1);

            pcid = _para.AddPresentationContext(SopClass.StudyRootQueryRetrieveInformationModelFind);
            _para.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);

            pcid = _para.AddPresentationContext(SopClass.PatientRootQueryRetrieveInformationModelFind);
            _para.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);

            pcid = _para.AddPresentationContext(SopClass.PatientStudyOnlyQueryRetrieveInformationModelFindRetired);
            _para.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);

            pcid = _para.AddPresentationContext(SopClass.PatientRootQueryRetrieveInformationModelMove);
            _para.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);

            pcid = _para.AddPresentationContext(SopClass.StudyRootQueryRetrieveInformationModelMove);
            _para.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);

            pcid = _para.AddPresentationContext(SopClass.PatientStudyOnlyQueryRetrieveInformationModelMoveRetired);
            _para.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
            _para.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);
            #endregion

            try
            {
                if (DicomServer.StartListening(_para, StartServer))
                {
                    IsStarted = true;
                    Logger.WriteLog("Started listen in local AE " + _para.CalledAE + " and port: " + _para.LocalEndPoint.Port);
                }
                else
                {
                    Logger.WriteLog("Can not listen in Port :" + _para.LocalEndPoint.Port);
                }
            }
            catch (System.Exception ex)
            {
                Logger.WriteLog(ex.Message);
            }
        }
        private static IDicomServerHandler StartServer(DicomServer server, ServerAssociationParameters assoc)
        {
            return new DicomServerHandler(server, assoc, LocalStoreDirectoryConfig);
        }

        public static void StopListenning()
        {
            if (_para != null)
            {
                DicomServer.StopListening(_para);
                IsStarted = false;
                Logger.WriteLog("Stoped listen in local AE " + _para.CalledAE + " and port: " + _para.LocalEndPoint.Port);
            }
        }

        #endregion
    }
}
